<!doctype html>

<html>
<head>
  <link rel="shortcut icon" href="static/images/favicon.ico" type="image/x-icon">
  <title>multitestrunner.js (Closure Library API Documentation - JavaScript)</title>
  <link rel="stylesheet" href="static/css/base.css">
  <link rel="stylesheet" href="static/css/doc.css">
  <link rel="stylesheet" href="static/css/sidetree.css">
  <link rel="stylesheet" href="static/css/prettify.css">

  <script>
     var _staticFilePath = "static/";
     var _typeTreeName = "goog";
     var _fileTreeName = "Source";
  </script>

  <script src="static/js/doc.js">
  </script>


  <meta charset="utf8">
</head>

<body onload="grokdoc.onLoad();">

<div id="header">
  <div class="g-section g-tpl-50-50 g-split">
    <div class="g-unit g-first">
      <a id="logo" href="index.html">Closure Library API Documentation</a>
    </div>

    <div class="g-unit">
      <div class="g-c">
        <strong>Go to class or file:</strong>
        <input type="text" id="ac">
      </div>
    </div>
  </div>
</div>

<div class="clear"></div>

<h2><a href="closure_goog_testing_multitestrunner.js.html">multitestrunner.js</a></h2>

<pre class="prettyprint lang-js">
<a name="line1"></a>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
<a name="line2"></a>//
<a name="line3"></a>// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
<a name="line4"></a>// you may not use this file except in compliance with the License.
<a name="line5"></a>// You may obtain a copy of the License at
<a name="line6"></a>//
<a name="line7"></a>//      http://www.apache.org/licenses/LICENSE-2.0
<a name="line8"></a>//
<a name="line9"></a>// Unless required by applicable law or agreed to in writing, software
<a name="line10"></a>// distributed under the License is distributed on an &quot;AS-IS&quot; BASIS,
<a name="line11"></a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a name="line12"></a>// See the License for the specific language governing permissions and
<a name="line13"></a>// limitations under the License.
<a name="line14"></a>
<a name="line15"></a>/**
<a name="line16"></a> * @fileoverview Utility for running multiple test files that utilize the same
<a name="line17"></a> * interface as goog.testing.TestRunner.  Each test is run in series and their
<a name="line18"></a> * results aggregated.  The main usecase for the MultiTestRunner is to allow
<a name="line19"></a> * the testing of all tests in a project locally.
<a name="line20"></a> *
<a name="line21"></a> */
<a name="line22"></a>
<a name="line23"></a>goog.provide(&#39;goog.testing.MultiTestRunner&#39;);
<a name="line24"></a>goog.provide(&#39;goog.testing.MultiTestRunner.TestFrame&#39;);
<a name="line25"></a>
<a name="line26"></a>goog.require(&#39;goog.Timer&#39;);
<a name="line27"></a>goog.require(&#39;goog.array&#39;);
<a name="line28"></a>goog.require(&#39;goog.dom&#39;);
<a name="line29"></a>goog.require(&#39;goog.dom.classes&#39;);
<a name="line30"></a>goog.require(&#39;goog.events.EventHandler&#39;);
<a name="line31"></a>goog.require(&#39;goog.functions&#39;);
<a name="line32"></a>goog.require(&#39;goog.string&#39;);
<a name="line33"></a>goog.require(&#39;goog.ui.Component&#39;);
<a name="line34"></a>goog.require(&#39;goog.ui.ServerChart&#39;);
<a name="line35"></a>goog.require(&#39;goog.ui.ServerChart.ChartType&#39;);
<a name="line36"></a>goog.require(&#39;goog.ui.TableSorter&#39;);
<a name="line37"></a>
<a name="line38"></a>
<a name="line39"></a>
<a name="line40"></a>/**
<a name="line41"></a> * A component for running multiple tests within the browser.
<a name="line42"></a> * @param {goog.dom.DomHelper=} opt_domHelper A DOM helper.
<a name="line43"></a> * @extends {goog.ui.Component}
<a name="line44"></a> * @constructor
<a name="line45"></a> */
<a name="line46"></a>goog.testing.MultiTestRunner = function(opt_domHelper) {
<a name="line47"></a>  goog.ui.Component.call(this, opt_domHelper);
<a name="line48"></a>
<a name="line49"></a>  /**
<a name="line50"></a>   * Array of tests to execute, when combined with the base path this should be
<a name="line51"></a>   * a relative path to the test from the page containing the multi testrunner.
<a name="line52"></a>   * @type {Array.&lt;string&gt;}
<a name="line53"></a>   * @private
<a name="line54"></a>   */
<a name="line55"></a>  this.allTests_ = [];
<a name="line56"></a>
<a name="line57"></a>  /**
<a name="line58"></a>   * Tests that match the filter function.
<a name="line59"></a>   * @type {Array.&lt;string&gt;}
<a name="line60"></a>   * @private
<a name="line61"></a>   */
<a name="line62"></a>  this.activeTests_ = [];
<a name="line63"></a>
<a name="line64"></a>  /**
<a name="line65"></a>   * An event handler for handling events.
<a name="line66"></a>   * @type {goog.events.EventHandler}
<a name="line67"></a>   * @private
<a name="line68"></a>   */
<a name="line69"></a>  this.eh_ = new goog.events.EventHandler(this);
<a name="line70"></a>
<a name="line71"></a>  /**
<a name="line72"></a>   * A table sorter for the stats.
<a name="line73"></a>   * @type {goog.ui.TableSorter}
<a name="line74"></a>   * @private
<a name="line75"></a>   */
<a name="line76"></a>  this.tableSorter_ = new goog.ui.TableSorter(this.dom_);
<a name="line77"></a>};
<a name="line78"></a>goog.inherits(goog.testing.MultiTestRunner, goog.ui.Component);
<a name="line79"></a>
<a name="line80"></a>
<a name="line81"></a>/**
<a name="line82"></a> * Default maximimum amount of time to spend at each stage of the test.
<a name="line83"></a> * @type {number}
<a name="line84"></a> */
<a name="line85"></a>goog.testing.MultiTestRunner.DEFAULT_TIMEOUT_MS = 45 * 1000;
<a name="line86"></a>
<a name="line87"></a>
<a name="line88"></a>/**
<a name="line89"></a> * Messages corresponding to the numeric states.
<a name="line90"></a> * @type {Array.&lt;string&gt;}
<a name="line91"></a> */
<a name="line92"></a>goog.testing.MultiTestRunner.STATES = [
<a name="line93"></a>  &#39;waiting for test runner&#39;,
<a name="line94"></a>  &#39;initializing tests&#39;,
<a name="line95"></a>  &#39;waiting for tests to finish&#39;
<a name="line96"></a>];
<a name="line97"></a>
<a name="line98"></a>
<a name="line99"></a>/**
<a name="line100"></a> * The test suite&#39;s name.
<a name="line101"></a> * @type {string} name
<a name="line102"></a> * @private
<a name="line103"></a> */
<a name="line104"></a>goog.testing.MultiTestRunner.prototype.name_ = &#39;&#39;;
<a name="line105"></a>
<a name="line106"></a>
<a name="line107"></a>/**
<a name="line108"></a> * The base path used to resolve files within the allTests_ array.
<a name="line109"></a> * @type {string}
<a name="line110"></a> * @private
<a name="line111"></a> */
<a name="line112"></a>goog.testing.MultiTestRunner.prototype.basePath_ = &#39;&#39;;
<a name="line113"></a>
<a name="line114"></a>
<a name="line115"></a>/**
<a name="line116"></a> * A set of tests that have finished.  All extant keys map to true.
<a name="line117"></a> * @type {Object.&lt;boolean&gt;}
<a name="line118"></a> * @private
<a name="line119"></a> */
<a name="line120"></a>goog.testing.MultiTestRunner.prototype.finished_ = null;
<a name="line121"></a>
<a name="line122"></a>
<a name="line123"></a>/**
<a name="line124"></a> * Whether the report should contain verbose information about the passes.
<a name="line125"></a> * @type {boolean}
<a name="line126"></a> * @private
<a name="line127"></a> */
<a name="line128"></a>goog.testing.MultiTestRunner.prototype.verbosePasses_ = false;
<a name="line129"></a>
<a name="line130"></a>
<a name="line131"></a>/**
<a name="line132"></a> * Whether to hide passing tests completely in the report, makes verbosePasses_
<a name="line133"></a> * obsolete.
<a name="line134"></a> * @type {boolean}
<a name="line135"></a> * @private
<a name="line136"></a> */
<a name="line137"></a>goog.testing.MultiTestRunner.prototype.hidePasses_ = false;
<a name="line138"></a>
<a name="line139"></a>
<a name="line140"></a>/**
<a name="line141"></a> * Flag used to tell the test runner to stop after the current test.
<a name="line142"></a> * @type {boolean}
<a name="line143"></a> * @private
<a name="line144"></a> */
<a name="line145"></a>goog.testing.MultiTestRunner.prototype.stopped_ = false;
<a name="line146"></a>
<a name="line147"></a>
<a name="line148"></a>/**
<a name="line149"></a> * Flag indicating whether the test runner is active.
<a name="line150"></a> * @type {boolean}
<a name="line151"></a> * @private
<a name="line152"></a> */
<a name="line153"></a>goog.testing.MultiTestRunner.prototype.active_ = false;
<a name="line154"></a>
<a name="line155"></a>
<a name="line156"></a>/**
<a name="line157"></a> * Index of the next test to run.
<a name="line158"></a> * @type {number}
<a name="line159"></a> * @private
<a name="line160"></a> */
<a name="line161"></a>goog.testing.MultiTestRunner.prototype.startedCount_ = 0;
<a name="line162"></a>
<a name="line163"></a>
<a name="line164"></a>/**
<a name="line165"></a> * Count of the results received so far.
<a name="line166"></a> * @type {number}
<a name="line167"></a> * @private
<a name="line168"></a> */
<a name="line169"></a>goog.testing.MultiTestRunner.prototype.resultCount_ = 0;
<a name="line170"></a>
<a name="line171"></a>
<a name="line172"></a>/**
<a name="line173"></a> * Number of passes so far.
<a name="line174"></a> * @type {number}
<a name="line175"></a> * @private
<a name="line176"></a> */
<a name="line177"></a>goog.testing.MultiTestRunner.prototype.passes_ = 0;
<a name="line178"></a>
<a name="line179"></a>
<a name="line180"></a>/**
<a name="line181"></a> * Timestamp for the current start time.
<a name="line182"></a> * @type {number}
<a name="line183"></a> * @private
<a name="line184"></a> */
<a name="line185"></a>goog.testing.MultiTestRunner.prototype.startTime_ = 0;
<a name="line186"></a>
<a name="line187"></a>
<a name="line188"></a>/**
<a name="line189"></a> * Only tests whose paths patch this filter function will be
<a name="line190"></a> * executed.
<a name="line191"></a> * @type {function(string): boolean}
<a name="line192"></a> * @private
<a name="line193"></a> */
<a name="line194"></a>goog.testing.MultiTestRunner.prototype.filterFn_ = goog.functions.TRUE;
<a name="line195"></a>
<a name="line196"></a>
<a name="line197"></a>/**
<a name="line198"></a> * Number of milliseconds to wait for loading and initialization steps.
<a name="line199"></a> * @type {number}
<a name="line200"></a> * @private
<a name="line201"></a> */
<a name="line202"></a>goog.testing.MultiTestRunner.prototype.timeoutMs_ =
<a name="line203"></a>    goog.testing.MultiTestRunner.DEFAULT_TIMEOUT_MS;
<a name="line204"></a>
<a name="line205"></a>
<a name="line206"></a>/**
<a name="line207"></a> * An array of objects containing stats about the tests.
<a name="line208"></a> * @type {Array.&lt;Object&gt;?}
<a name="line209"></a> * @private
<a name="line210"></a> */
<a name="line211"></a>goog.testing.MultiTestRunner.prototype.stats_ = null;
<a name="line212"></a>
<a name="line213"></a>
<a name="line214"></a>/**
<a name="line215"></a> * Reference to the start button element.
<a name="line216"></a> * @type {Element}
<a name="line217"></a> * @private
<a name="line218"></a> */
<a name="line219"></a>goog.testing.MultiTestRunner.prototype.startButtonEl_ = null;
<a name="line220"></a>
<a name="line221"></a>
<a name="line222"></a>/**
<a name="line223"></a> * Reference to the stop button element.
<a name="line224"></a> * @type {Element}
<a name="line225"></a> * @private
<a name="line226"></a> */
<a name="line227"></a>goog.testing.MultiTestRunner.prototype.stopButtonEl_ = null;
<a name="line228"></a>
<a name="line229"></a>
<a name="line230"></a>/**
<a name="line231"></a> * Reference to the log element.
<a name="line232"></a> * @type {Element}
<a name="line233"></a> * @private
<a name="line234"></a> */
<a name="line235"></a>goog.testing.MultiTestRunner.prototype.logEl_ = null;
<a name="line236"></a>
<a name="line237"></a>
<a name="line238"></a>/**
<a name="line239"></a> * Reference to the report element.
<a name="line240"></a> * @type {Element}
<a name="line241"></a> * @private
<a name="line242"></a> */
<a name="line243"></a>goog.testing.MultiTestRunner.prototype.reportEl_ = null;
<a name="line244"></a>
<a name="line245"></a>
<a name="line246"></a>/**
<a name="line247"></a> * Reference to the stats element.
<a name="line248"></a> * @type {Element}
<a name="line249"></a> * @private
<a name="line250"></a> */
<a name="line251"></a>goog.testing.MultiTestRunner.prototype.statsEl_ = null;
<a name="line252"></a>
<a name="line253"></a>
<a name="line254"></a>/**
<a name="line255"></a> * Reference to the progress bar&#39;s element.
<a name="line256"></a> * @type {Element}
<a name="line257"></a> * @private
<a name="line258"></a> */
<a name="line259"></a>goog.testing.MultiTestRunner.prototype.progressEl_ = null;
<a name="line260"></a>
<a name="line261"></a>
<a name="line262"></a>/**
<a name="line263"></a> * Reference to the progress bar&#39;s inner row element.
<a name="line264"></a> * @type {Element}
<a name="line265"></a> * @private
<a name="line266"></a> */
<a name="line267"></a>goog.testing.MultiTestRunner.prototype.progressRow_ = null;
<a name="line268"></a>
<a name="line269"></a>
<a name="line270"></a>/**
<a name="line271"></a> * Reference to the log tab.
<a name="line272"></a> * @type {Element}
<a name="line273"></a> * @private
<a name="line274"></a> */
<a name="line275"></a>goog.testing.MultiTestRunner.prototype.logTabEl_ = null;
<a name="line276"></a>
<a name="line277"></a>
<a name="line278"></a>/**
<a name="line279"></a> * Reference to the report tab.
<a name="line280"></a> * @type {Element}
<a name="line281"></a> * @private
<a name="line282"></a> */
<a name="line283"></a>goog.testing.MultiTestRunner.prototype.reportTabEl_ = null;
<a name="line284"></a>
<a name="line285"></a>
<a name="line286"></a>/**
<a name="line287"></a> * Reference to the stats tab.
<a name="line288"></a> * @type {Element}
<a name="line289"></a> * @private
<a name="line290"></a> */
<a name="line291"></a>goog.testing.MultiTestRunner.prototype.statsTabEl_ = null;
<a name="line292"></a>
<a name="line293"></a>
<a name="line294"></a>/**
<a name="line295"></a> * The number of tests to run at a time.
<a name="line296"></a> * @type {number}
<a name="line297"></a> * @private
<a name="line298"></a> */
<a name="line299"></a>goog.testing.MultiTestRunner.prototype.poolSize_ = 1;
<a name="line300"></a>
<a name="line301"></a>
<a name="line302"></a>/**
<a name="line303"></a> * The size of the stats bucket for the number of files loaded histogram.
<a name="line304"></a> * @type {number}
<a name="line305"></a> * @private
<a name="line306"></a> */
<a name="line307"></a>goog.testing.MultiTestRunner.prototype.numFilesStatsBucketSize_ = 20;
<a name="line308"></a>
<a name="line309"></a>
<a name="line310"></a>/**
<a name="line311"></a> * The size of the stats bucket in ms for the run time histogram.
<a name="line312"></a> * @type {number}
<a name="line313"></a> * @private
<a name="line314"></a> */
<a name="line315"></a>goog.testing.MultiTestRunner.prototype.runTimeStatsBucketSize_ = 500;
<a name="line316"></a>
<a name="line317"></a>
<a name="line318"></a>/**
<a name="line319"></a> * Sets the name for the test suite.
<a name="line320"></a> * @param {string} name The suite&#39;s name.
<a name="line321"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line322"></a> */
<a name="line323"></a>goog.testing.MultiTestRunner.prototype.setName = function(name) {
<a name="line324"></a>  this.name_ = name;
<a name="line325"></a>  return this;
<a name="line326"></a>};
<a name="line327"></a>
<a name="line328"></a>
<a name="line329"></a>/**
<a name="line330"></a> * Returns the name for the test suite.
<a name="line331"></a> * @return {string} The name for the test suite.
<a name="line332"></a> */
<a name="line333"></a>goog.testing.MultiTestRunner.prototype.getName = function() {
<a name="line334"></a>  return this.name_;
<a name="line335"></a>};
<a name="line336"></a>
<a name="line337"></a>
<a name="line338"></a>/**
<a name="line339"></a> * Sets the basepath that tests added using addTests are resolved with.
<a name="line340"></a> * @param {string} path The relative basepath.
<a name="line341"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line342"></a> */
<a name="line343"></a>goog.testing.MultiTestRunner.prototype.setBasePath = function(path) {
<a name="line344"></a>  this.basePath_ = path;
<a name="line345"></a>  return this;
<a name="line346"></a>};
<a name="line347"></a>
<a name="line348"></a>
<a name="line349"></a>/**
<a name="line350"></a> * Returns the basepath that tests added using addTests are resolved with.
<a name="line351"></a> * @return {string} The basepath that tests added using addTests are resolved
<a name="line352"></a> *     with.
<a name="line353"></a> */
<a name="line354"></a>goog.testing.MultiTestRunner.prototype.getBasePath = function() {
<a name="line355"></a>  return this.basePath_;
<a name="line356"></a>};
<a name="line357"></a>
<a name="line358"></a>
<a name="line359"></a>/**
<a name="line360"></a> * Sets whether the report should contain verbose information for tests that
<a name="line361"></a> * pass.
<a name="line362"></a> * @param {boolean} verbose Whether report should be verbose.
<a name="line363"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line364"></a> */
<a name="line365"></a>goog.testing.MultiTestRunner.prototype.setVerbosePasses = function(verbose) {
<a name="line366"></a>  this.verbosePasses_ = verbose;
<a name="line367"></a>  return this;
<a name="line368"></a>};
<a name="line369"></a>
<a name="line370"></a>
<a name="line371"></a>/**
<a name="line372"></a> * Returns whether the report should contain verbose information for tests that
<a name="line373"></a> * pass.
<a name="line374"></a> * @return {boolean} Whether the report should contain verbose information for
<a name="line375"></a> *     tests that pass.
<a name="line376"></a> */
<a name="line377"></a>goog.testing.MultiTestRunner.prototype.getVerbosePasses = function() {
<a name="line378"></a>  return this.verbosePasses_;
<a name="line379"></a>};
<a name="line380"></a>
<a name="line381"></a>
<a name="line382"></a>/**
<a name="line383"></a> * Sets whether the report should contain passing tests at all, makes
<a name="line384"></a> * setVerbosePasses obsolete.
<a name="line385"></a> * @param {boolean} hide Whether report should not contain passing tests.
<a name="line386"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line387"></a> */
<a name="line388"></a>goog.testing.MultiTestRunner.prototype.setHidePasses = function(hide) {
<a name="line389"></a>  this.hidePasses_ = hide;
<a name="line390"></a>  return this;
<a name="line391"></a>};
<a name="line392"></a>
<a name="line393"></a>
<a name="line394"></a>/**
<a name="line395"></a> * Returns whether the report should contain passing tests at all, makes
<a name="line396"></a> * setVerbosePasses obsolete.
<a name="line397"></a> * @return {boolean} Whether the report should contain passing tests at all,
<a name="line398"></a> *     makes setVerbosePasses obsolete.
<a name="line399"></a> */
<a name="line400"></a>goog.testing.MultiTestRunner.prototype.getHidePasses = function() {
<a name="line401"></a>  return this.hidePasses_;
<a name="line402"></a>};
<a name="line403"></a>
<a name="line404"></a>
<a name="line405"></a>/**
<a name="line406"></a> * Sets the bucket sizes for the histograms.
<a name="line407"></a> * @param {number} f Bucket size for num files loaded histogram.
<a name="line408"></a> * @param {number} t Bucket size for run time histogram.
<a name="line409"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line410"></a> */
<a name="line411"></a>goog.testing.MultiTestRunner.prototype.setStatsBucketSizes = function(f, t) {
<a name="line412"></a>  this.numFilesStatsBucketSize_ = f;
<a name="line413"></a>  this.runTimeStatsBucketSize_ = t;
<a name="line414"></a>  return this;
<a name="line415"></a>};
<a name="line416"></a>
<a name="line417"></a>
<a name="line418"></a>/**
<a name="line419"></a> * Sets the number of milliseconds to wait for the page to load, initialize and
<a name="line420"></a> * run the tests.
<a name="line421"></a> * @param {number} timeout Time in milliseconds.
<a name="line422"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line423"></a> */
<a name="line424"></a>goog.testing.MultiTestRunner.prototype.setTimeout = function(timeout) {
<a name="line425"></a>  this.timeoutMs_ = timeout;
<a name="line426"></a>  return this;
<a name="line427"></a>};
<a name="line428"></a>
<a name="line429"></a>
<a name="line430"></a>/**
<a name="line431"></a> * Returns the number of milliseconds to wait for the page to load, initialize
<a name="line432"></a> * and run the tests.
<a name="line433"></a> * @return {number} The number of milliseconds to wait for the page to load,
<a name="line434"></a> *     initialize and run the tests.
<a name="line435"></a> */
<a name="line436"></a>goog.testing.MultiTestRunner.prototype.getTimeout = function() {
<a name="line437"></a>  return this.timeoutMs_;
<a name="line438"></a>};
<a name="line439"></a>
<a name="line440"></a>
<a name="line441"></a>/**
<a name="line442"></a> * Sets the number of tests that can be run at the same time. This only improves
<a name="line443"></a> * performance due to the amount of time spent loading the tests.
<a name="line444"></a> * @param {number} size The number of tests to run at a time.
<a name="line445"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line446"></a> */
<a name="line447"></a>goog.testing.MultiTestRunner.prototype.setPoolSize = function(size) {
<a name="line448"></a>  this.poolSize_ = size;
<a name="line449"></a>  return this;
<a name="line450"></a>};
<a name="line451"></a>
<a name="line452"></a>
<a name="line453"></a>/**
<a name="line454"></a> * Returns the number of tests that can be run at the same time. This only
<a name="line455"></a> * improves performance due to the amount of time spent loading the tests.
<a name="line456"></a> * @return {number} The number of tests that can be run at the same time. This
<a name="line457"></a> *     only improves performance due to the amount of time spent loading the
<a name="line458"></a> *     tests.
<a name="line459"></a> */
<a name="line460"></a>goog.testing.MultiTestRunner.prototype.getPoolSize = function() {
<a name="line461"></a>  return this.poolSize_;
<a name="line462"></a>};
<a name="line463"></a>
<a name="line464"></a>
<a name="line465"></a>/**
<a name="line466"></a> * Sets a filter function. Only test paths that match the filter function
<a name="line467"></a> * will be executed.
<a name="line468"></a> * @param {function(string): boolean} filterFn Filters test paths.
<a name="line469"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line470"></a> */
<a name="line471"></a>goog.testing.MultiTestRunner.prototype.setFilterFunction = function(filterFn) {
<a name="line472"></a>  this.filterFn_ = filterFn;
<a name="line473"></a>  return this;
<a name="line474"></a>};
<a name="line475"></a>
<a name="line476"></a>
<a name="line477"></a>/**
<a name="line478"></a> * Returns a filter function. Only test paths that match the filter function
<a name="line479"></a> * will be executed.
<a name="line480"></a> * @return {function(string): boolean} A filter function. Only test paths that
<a name="line481"></a> *     match the filter function will be executed.
<a name="line482"></a>
<a name="line483"></a> */
<a name="line484"></a>goog.testing.MultiTestRunner.prototype.getFilterFunction = function() {
<a name="line485"></a>  return this.filterFn_;
<a name="line486"></a>};
<a name="line487"></a>
<a name="line488"></a>
<a name="line489"></a>/**
<a name="line490"></a> * Adds an array of tests to the tests that the test runner should execute.
<a name="line491"></a> * @param {Array.&lt;string&gt;} tests Adds tests to the test runner.
<a name="line492"></a> * @return {goog.testing.MultiTestRunner} Instance for chaining.
<a name="line493"></a> */
<a name="line494"></a>goog.testing.MultiTestRunner.prototype.addTests = function(tests) {
<a name="line495"></a>  goog.array.extend(this.allTests_, tests);
<a name="line496"></a>  return this;
<a name="line497"></a>};
<a name="line498"></a>
<a name="line499"></a>
<a name="line500"></a>/**
<a name="line501"></a> * Returns the list of all tests added to the runner.
<a name="line502"></a> * @return {Array.&lt;string&gt;} The list of all tests added to the runner.
<a name="line503"></a> */
<a name="line504"></a>goog.testing.MultiTestRunner.prototype.getAllTests = function() {
<a name="line505"></a>  return this.allTests_;
<a name="line506"></a>};
<a name="line507"></a>
<a name="line508"></a>
<a name="line509"></a>/**
<a name="line510"></a> * Returns the list of tests that will be run when start() is called.
<a name="line511"></a> * @return {Array.&lt;string&gt;} The list of tests that will be run when start() is
<a name="line512"></a> *     called.
<a name="line513"></a> */
<a name="line514"></a>goog.testing.MultiTestRunner.prototype.getTestsToRun = function() {
<a name="line515"></a>  return goog.array.filter(this.allTests_, this.filterFn_);
<a name="line516"></a>};
<a name="line517"></a>
<a name="line518"></a>
<a name="line519"></a>/**
<a name="line520"></a> * Returns a list of tests from runner that have been marked as failed.
<a name="line521"></a> * @return {Array.&lt;string&gt;} A list of tests from runner that have been marked as
<a name="line522"></a> *     failed.
<a name="line523"></a> */
<a name="line524"></a>goog.testing.MultiTestRunner.prototype.getTestsThatFailed = function() {
<a name="line525"></a>  var stats = this.stats_;
<a name="line526"></a>  var failedTests = [];
<a name="line527"></a>  if (stats) {
<a name="line528"></a>    for (var i = 0, stat; stat = stats[i]; i++) {
<a name="line529"></a>      if (!stat.success) {
<a name="line530"></a>        failedTests.push(stat.testFile);
<a name="line531"></a>      }
<a name="line532"></a>    }
<a name="line533"></a>  }
<a name="line534"></a>  return failedTests;
<a name="line535"></a>};
<a name="line536"></a>
<a name="line537"></a>
<a name="line538"></a>/**
<a name="line539"></a> * Deletes and re-creates the progress table inside the progess element.
<a name="line540"></a> * @private
<a name="line541"></a> */
<a name="line542"></a>goog.testing.MultiTestRunner.prototype.resetProgressDom_ = function() {
<a name="line543"></a>  goog.dom.removeChildren(this.progressEl_);
<a name="line544"></a>  var progressTable = this.dom_.createDom(&#39;table&#39;);
<a name="line545"></a>  var progressTBody = this.dom_.createDom(&#39;tbody&#39;);
<a name="line546"></a>  this.progressRow_ = this.dom_.createDom(&#39;tr&#39;);
<a name="line547"></a>  for (var i = 0; i &lt; this.activeTests_.length; i++) {
<a name="line548"></a>    var progressCell = this.dom_.createDom(&#39;td&#39;);
<a name="line549"></a>    this.progressRow_.appendChild(progressCell);
<a name="line550"></a>  }
<a name="line551"></a>  progressTBody.appendChild(this.progressRow_);
<a name="line552"></a>  progressTable.appendChild(progressTBody);
<a name="line553"></a>  this.progressEl_.appendChild(progressTable);
<a name="line554"></a>};
<a name="line555"></a>
<a name="line556"></a>
<a name="line557"></a>/** @override */
<a name="line558"></a>goog.testing.MultiTestRunner.prototype.createDom = function() {
<a name="line559"></a>  goog.testing.MultiTestRunner.superClass_.createDom.call(this);
<a name="line560"></a>  var el = this.getElement();
<a name="line561"></a>  el.className = goog.getCssName(&#39;goog-testrunner&#39;);
<a name="line562"></a>
<a name="line563"></a>  this.progressEl_ = this.dom_.createDom(&#39;div&#39;);
<a name="line564"></a>  this.progressEl_.className = goog.getCssName(&#39;goog-testrunner-progress&#39;);
<a name="line565"></a>  el.appendChild(this.progressEl_);
<a name="line566"></a>
<a name="line567"></a>  var buttons = this.dom_.createDom(&#39;div&#39;);
<a name="line568"></a>  buttons.className = goog.getCssName(&#39;goog-testrunner-buttons&#39;);
<a name="line569"></a>  this.startButtonEl_ = this.dom_.createDom(&#39;button&#39;, null, &#39;Start&#39;);
<a name="line570"></a>  this.stopButtonEl_ =
<a name="line571"></a>      this.dom_.createDom(&#39;button&#39;, {&#39;disabled&#39;: true}, &#39;Stop&#39;);
<a name="line572"></a>  buttons.appendChild(this.startButtonEl_);
<a name="line573"></a>  buttons.appendChild(this.stopButtonEl_);
<a name="line574"></a>  el.appendChild(buttons);
<a name="line575"></a>
<a name="line576"></a>  this.eh_.listen(this.startButtonEl_, &#39;click&#39;,
<a name="line577"></a>      this.onStartClicked_);
<a name="line578"></a>  this.eh_.listen(this.stopButtonEl_, &#39;click&#39;,
<a name="line579"></a>      this.onStopClicked_);
<a name="line580"></a>
<a name="line581"></a>  this.logEl_ = this.dom_.createElement(&#39;div&#39;);
<a name="line582"></a>  this.logEl_.className = goog.getCssName(&#39;goog-testrunner-log&#39;);
<a name="line583"></a>  el.appendChild(this.logEl_);
<a name="line584"></a>
<a name="line585"></a>  this.reportEl_ = this.dom_.createElement(&#39;div&#39;);
<a name="line586"></a>  this.reportEl_.className = goog.getCssName(&#39;goog-testrunner-report&#39;);
<a name="line587"></a>  this.reportEl_.style.display = &#39;none&#39;;
<a name="line588"></a>  el.appendChild(this.reportEl_);
<a name="line589"></a>
<a name="line590"></a>  this.statsEl_ = this.dom_.createElement(&#39;div&#39;);
<a name="line591"></a>  this.statsEl_.className = goog.getCssName(&#39;goog-testrunner-stats&#39;);
<a name="line592"></a>  this.statsEl_.style.display = &#39;none&#39;;
<a name="line593"></a>  el.appendChild(this.statsEl_);
<a name="line594"></a>
<a name="line595"></a>  this.logTabEl_ = this.dom_.createDom(&#39;div&#39;, null, &#39;Log&#39;);
<a name="line596"></a>  this.logTabEl_.className = goog.getCssName(&#39;goog-testrunner-logtab&#39;) + &#39; &#39; +
<a name="line597"></a>      goog.getCssName(&#39;goog-testrunner-activetab&#39;);
<a name="line598"></a>  el.appendChild(this.logTabEl_);
<a name="line599"></a>
<a name="line600"></a>  this.reportTabEl_ = this.dom_.createDom(&#39;div&#39;, null, &#39;Report&#39;);
<a name="line601"></a>  this.reportTabEl_.className = goog.getCssName(&#39;goog-testrunner-reporttab&#39;);
<a name="line602"></a>  el.appendChild(this.reportTabEl_);
<a name="line603"></a>
<a name="line604"></a>  this.statsTabEl_ = this.dom_.createDom(&#39;div&#39;, null, &#39;Stats&#39;);
<a name="line605"></a>  this.statsTabEl_.className = goog.getCssName(&#39;goog-testrunner-statstab&#39;);
<a name="line606"></a>  el.appendChild(this.statsTabEl_);
<a name="line607"></a>
<a name="line608"></a>  this.eh_.listen(this.logTabEl_, &#39;click&#39;, this.onLogTabClicked_);
<a name="line609"></a>  this.eh_.listen(this.reportTabEl_, &#39;click&#39;, this.onReportTabClicked_);
<a name="line610"></a>  this.eh_.listen(this.statsTabEl_, &#39;click&#39;, this.onStatsTabClicked_);
<a name="line611"></a>
<a name="line612"></a>};
<a name="line613"></a>
<a name="line614"></a>
<a name="line615"></a>/** @override */
<a name="line616"></a>goog.testing.MultiTestRunner.prototype.disposeInternal = function() {
<a name="line617"></a>  goog.testing.MultiTestRunner.superClass_.disposeInternal.call(this);
<a name="line618"></a>  this.tableSorter_.dispose();
<a name="line619"></a>  this.eh_.dispose();
<a name="line620"></a>  this.startButtonEl_ = null;
<a name="line621"></a>  this.stopButtonEl_ = null;
<a name="line622"></a>  this.logEl_ = null;
<a name="line623"></a>  this.reportEl_ = null;
<a name="line624"></a>  this.progressEl_ = null;
<a name="line625"></a>  this.logTabEl_ = null;
<a name="line626"></a>  this.reportTabEl_ = null;
<a name="line627"></a>  this.statsTabEl_ = null;
<a name="line628"></a>  this.statsEl_ = null;
<a name="line629"></a>};
<a name="line630"></a>
<a name="line631"></a>
<a name="line632"></a>/**
<a name="line633"></a> * Starts executing the tests.
<a name="line634"></a> */
<a name="line635"></a>goog.testing.MultiTestRunner.prototype.start = function() {
<a name="line636"></a>  this.startButtonEl_.disabled = true;
<a name="line637"></a>  this.stopButtonEl_.disabled = false;
<a name="line638"></a>  this.stopped_ = false;
<a name="line639"></a>  this.active_ = true;
<a name="line640"></a>  this.finished_ = {};
<a name="line641"></a>  this.activeTests_ = this.getTestsToRun();
<a name="line642"></a>  this.startedCount_ = 0;
<a name="line643"></a>  this.resultCount_ = 0;
<a name="line644"></a>  this.passes_ = 0;
<a name="line645"></a>  this.stats_ = [];
<a name="line646"></a>  this.startTime_ = goog.now();
<a name="line647"></a>
<a name="line648"></a>  this.resetProgressDom_();
<a name="line649"></a>  goog.dom.removeChildren(this.logEl_);
<a name="line650"></a>
<a name="line651"></a>  this.resetReport_();
<a name="line652"></a>  this.clearStats_();
<a name="line653"></a>  this.showTab_(0);
<a name="line654"></a>
<a name="line655"></a>  // Ensure the pool isn&#39;t too big.
<a name="line656"></a>  while (this.getChildCount() &gt; this.poolSize_) {
<a name="line657"></a>    this.removeChildAt(0, true).dispose();
<a name="line658"></a>  }
<a name="line659"></a>
<a name="line660"></a>  // Start a test in each runner.
<a name="line661"></a>  for (var i = 0; i &lt; this.poolSize_; i++) {
<a name="line662"></a>    if (i &gt;= this.getChildCount()) {
<a name="line663"></a>      var testFrame = new goog.testing.MultiTestRunner.TestFrame(
<a name="line664"></a>          this.basePath_, this.timeoutMs_, this.verbosePasses_, this.dom_);
<a name="line665"></a>      this.addChild(testFrame, true);
<a name="line666"></a>    }
<a name="line667"></a>    this.runNextTest_(
<a name="line668"></a>        /** @type {goog.testing.MultiTestRunner.TestFrame} */
<a name="line669"></a>        (this.getChildAt(i)));
<a name="line670"></a>  }
<a name="line671"></a>};
<a name="line672"></a>
<a name="line673"></a>
<a name="line674"></a>/**
<a name="line675"></a> * Logs a message to the log window.
<a name="line676"></a> * @param {string} msg A message to log.
<a name="line677"></a> */
<a name="line678"></a>goog.testing.MultiTestRunner.prototype.log = function(msg) {
<a name="line679"></a>  if (msg != &#39;.&#39;) {
<a name="line680"></a>    msg = this.getTimeStamp_() + &#39; : &#39; + msg;
<a name="line681"></a>  }
<a name="line682"></a>
<a name="line683"></a>  this.logEl_.appendChild(this.dom_.createDom(&#39;div&#39;, null, msg));
<a name="line684"></a>
<a name="line685"></a>  // Autoscroll if we&#39;re near the bottom.
<a name="line686"></a>  var top = this.logEl_.scrollTop;
<a name="line687"></a>  var height = this.logEl_.scrollHeight - this.logEl_.offsetHeight;
<a name="line688"></a>  if (top == 0 || top &gt; height - 50) {
<a name="line689"></a>    this.logEl_.scrollTop = height;
<a name="line690"></a>  }
<a name="line691"></a>};
<a name="line692"></a>
<a name="line693"></a>
<a name="line694"></a>/**
<a name="line695"></a> * Processes a result returned from a TestFrame.  If there are tests remaining
<a name="line696"></a> * it will trigger the next one to be run, otherwise if there are no tests and
<a name="line697"></a> * all results have been recieved then it will call finish.
<a name="line698"></a> * @param {goog.testing.MultiTestRunner.TestFrame} frame The frame that just
<a name="line699"></a> *     finished.
<a name="line700"></a> */
<a name="line701"></a>goog.testing.MultiTestRunner.prototype.processResult = function(frame) {
<a name="line702"></a>  var success = frame.isSuccess();
<a name="line703"></a>  var report = frame.getReport();
<a name="line704"></a>  var test = frame.getTestFile();
<a name="line705"></a>
<a name="line706"></a>  this.stats_.push(frame.getStats());
<a name="line707"></a>  this.finished_[test] = true;
<a name="line708"></a>
<a name="line709"></a>  var prefix = success ? &#39;&#39; : &#39;*** FAILURE *** &#39;;
<a name="line710"></a>  this.log(prefix +
<a name="line711"></a>      this.trimFileName_(test) + &#39; : &#39; + (success ? &#39;Passed&#39; : &#39;Failed&#39;));
<a name="line712"></a>
<a name="line713"></a>  this.resultCount_++;
<a name="line714"></a>
<a name="line715"></a>  if (success) {
<a name="line716"></a>    this.passes_++;
<a name="line717"></a>  }
<a name="line718"></a>
<a name="line719"></a>  this.drawProgressSegment_(test, success);
<a name="line720"></a>  this.writeCurrentSummary_();
<a name="line721"></a>  if (!(success &amp;&amp; this.hidePasses_)) {
<a name="line722"></a>    this.drawTestResult_(test, success, report);
<a name="line723"></a>  }
<a name="line724"></a>
<a name="line725"></a>  if (!this.stopped_ &amp;&amp; this.startedCount_ &lt; this.activeTests_.length) {
<a name="line726"></a>    this.runNextTest_(frame);
<a name="line727"></a>  } else if (this.resultCount_ == this.activeTests_.length) {
<a name="line728"></a>    this.finish_();
<a name="line729"></a>  }
<a name="line730"></a>};
<a name="line731"></a>
<a name="line732"></a>
<a name="line733"></a>/**
<a name="line734"></a> * Runs the next available test, if there are any left.
<a name="line735"></a> * @param {goog.testing.MultiTestRunner.TestFrame} frame Where to run the test.
<a name="line736"></a> * @private
<a name="line737"></a> */
<a name="line738"></a>goog.testing.MultiTestRunner.prototype.runNextTest_ = function(frame) {
<a name="line739"></a>  if (this.startedCount_ &lt; this.activeTests_.length) {
<a name="line740"></a>    var nextTest = this.activeTests_[this.startedCount_++];
<a name="line741"></a>    this.log(this.trimFileName_(nextTest) + &#39; : Loading&#39;);
<a name="line742"></a>    frame.runTest(nextTest);
<a name="line743"></a>  }
<a name="line744"></a>};
<a name="line745"></a>
<a name="line746"></a>
<a name="line747"></a>/**
<a name="line748"></a> * Handles the test finishing, processing the results and rendering the report.
<a name="line749"></a> * @private
<a name="line750"></a> */
<a name="line751"></a>goog.testing.MultiTestRunner.prototype.finish_ = function() {
<a name="line752"></a>  if (this.stopped_) {
<a name="line753"></a>    this.log(&#39;Stopped&#39;);
<a name="line754"></a>  } else {
<a name="line755"></a>    this.log(&#39;Finished&#39;);
<a name="line756"></a>  }
<a name="line757"></a>
<a name="line758"></a>  this.startButtonEl_.disabled = false;
<a name="line759"></a>  this.stopButtonEl_.disabled = true;
<a name="line760"></a>  this.active_ = false;
<a name="line761"></a>
<a name="line762"></a>  this.showTab_(1);
<a name="line763"></a>  this.drawStats_();
<a name="line764"></a>
<a name="line765"></a>  // Remove all the test frames
<a name="line766"></a>  while (this.getChildCount() &gt; 0) {
<a name="line767"></a>    this.removeChildAt(0, true).dispose();
<a name="line768"></a>  }
<a name="line769"></a>
<a name="line770"></a>  // Compute tests that did not finish before the stop button was hit.
<a name="line771"></a>  var unfinished = [];
<a name="line772"></a>  for (var i = 0; i &lt; this.activeTests_.length; i++) {
<a name="line773"></a>    var test = this.activeTests_[i];
<a name="line774"></a>    if (!this.finished_[test]) {
<a name="line775"></a>      unfinished.push(test);
<a name="line776"></a>    }
<a name="line777"></a>  }
<a name="line778"></a>
<a name="line779"></a>  if (unfinished.length) {
<a name="line780"></a>    this.reportEl_.appendChild(goog.dom.createDom(&#39;pre&#39;, undefined,
<a name="line781"></a>        &#39;Theses tests did not finish:\n&#39; + unfinished.join(&#39;\n&#39;)));
<a name="line782"></a>  }
<a name="line783"></a>};
<a name="line784"></a>
<a name="line785"></a>
<a name="line786"></a>/**
<a name="line787"></a> * Resets the report, clearing out all children and drawing the initial summary.
<a name="line788"></a> * @private
<a name="line789"></a> */
<a name="line790"></a>goog.testing.MultiTestRunner.prototype.resetReport_ = function() {
<a name="line791"></a>  goog.dom.removeChildren(this.reportEl_);
<a name="line792"></a>  var summary = this.dom_.createDom(&#39;div&#39;);
<a name="line793"></a>  summary.className = goog.getCssName(&#39;goog-testrunner-progress-summary&#39;);
<a name="line794"></a>  this.reportEl_.appendChild(summary);
<a name="line795"></a>  this.writeCurrentSummary_();
<a name="line796"></a>};
<a name="line797"></a>
<a name="line798"></a>
<a name="line799"></a>/**
<a name="line800"></a> * Draws the stats for the test run.
<a name="line801"></a> * @private
<a name="line802"></a> */
<a name="line803"></a>goog.testing.MultiTestRunner.prototype.drawStats_ = function() {
<a name="line804"></a>  this.drawFilesHistogram_();
<a name="line805"></a>
<a name="line806"></a>  // Only show time stats if pool size is 1, otherwise times are wrong.
<a name="line807"></a>  if (this.poolSize_ == 1) {
<a name="line808"></a>    this.drawRunTimePie_();
<a name="line809"></a>    this.drawTimeHistogram_();
<a name="line810"></a>  }
<a name="line811"></a>
<a name="line812"></a>  this.drawWorstTestsTable_();
<a name="line813"></a>};
<a name="line814"></a>
<a name="line815"></a>
<a name="line816"></a>/**
<a name="line817"></a> * Draws the histogram showing number of files loaded.
<a name="line818"></a> * @private
<a name="line819"></a> */
<a name="line820"></a>goog.testing.MultiTestRunner.prototype.drawFilesHistogram_ = function() {
<a name="line821"></a>  this.drawStatsHistogram_(
<a name="line822"></a>      &#39;numFilesLoaded&#39;,
<a name="line823"></a>      this.numFilesStatsBucketSize_,
<a name="line824"></a>      goog.functions.identity,
<a name="line825"></a>      500,
<a name="line826"></a>      &#39;Histogram showing distribution of\nnumber of files loaded per test&#39;);
<a name="line827"></a>};
<a name="line828"></a>
<a name="line829"></a>
<a name="line830"></a>/**
<a name="line831"></a> * Draws the histogram showing how long each test took to complete.
<a name="line832"></a> * @private
<a name="line833"></a> */
<a name="line834"></a>goog.testing.MultiTestRunner.prototype.drawTimeHistogram_ = function() {
<a name="line835"></a>  this.drawStatsHistogram_(
<a name="line836"></a>      &#39;totalTime&#39;,
<a name="line837"></a>      this.runTimeStatsBucketSize_,
<a name="line838"></a>      function(x) { return x / 1000; },
<a name="line839"></a>      500,
<a name="line840"></a>      &#39;Histogram showing distribution of\ntime spent running tests in s&#39;);
<a name="line841"></a>};
<a name="line842"></a>
<a name="line843"></a>
<a name="line844"></a>/**
<a name="line845"></a> * Draws a stats histogram.
<a name="line846"></a> * @param {string} statsField Field of the stats object to graph.
<a name="line847"></a> * @param {number} bucketSize The size for the histogram&#39;s buckets.
<a name="line848"></a> * @param {function(number, ...[*]): *} valueTransformFn Function for
<a name="line849"></a> *     transforming the x-labels value for display.
<a name="line850"></a> * @param {number} width The width in pixels of the graph.
<a name="line851"></a> * @param {string} title The graph&#39;s title.
<a name="line852"></a> * @private
<a name="line853"></a> */
<a name="line854"></a>goog.testing.MultiTestRunner.prototype.drawStatsHistogram_ = function(
<a name="line855"></a>    statsField, bucketSize, valueTransformFn, width, title) {
<a name="line856"></a>
<a name="line857"></a>  var hist = {}, data = [], xlabels = [], ylabels = [];
<a name="line858"></a>  var max = 0;
<a name="line859"></a>  for (var i = 0; i &lt; this.stats_.length; i++) {
<a name="line860"></a>    var num = this.stats_[i][statsField];
<a name="line861"></a>    var bucket = Math.floor(num / bucketSize) * bucketSize;
<a name="line862"></a>    if (bucket &gt; max) {
<a name="line863"></a>      max = bucket;
<a name="line864"></a>    }
<a name="line865"></a>    if (!hist[bucket]) {
<a name="line866"></a>      hist[bucket] = 1;
<a name="line867"></a>    } else {
<a name="line868"></a>      hist[bucket]++;
<a name="line869"></a>    }
<a name="line870"></a>  }
<a name="line871"></a>  var maxBucketSize = 0;
<a name="line872"></a>  for (var i = 0; i &lt;= max; i += bucketSize) {
<a name="line873"></a>    xlabels.push(valueTransformFn(i));
<a name="line874"></a>    var count = hist[i] || 0;
<a name="line875"></a>    if (count &gt; maxBucketSize) {
<a name="line876"></a>      maxBucketSize = count;
<a name="line877"></a>    }
<a name="line878"></a>    data.push(count);
<a name="line879"></a>  }
<a name="line880"></a>  var diff = Math.max(1, Math.ceil(maxBucketSize / 10));
<a name="line881"></a>  for (var i = 0; i &lt;= maxBucketSize; i += diff) {
<a name="line882"></a>    ylabels.push(i);
<a name="line883"></a>  }
<a name="line884"></a>  var chart = new goog.ui.ServerChart(
<a name="line885"></a>      goog.ui.ServerChart.ChartType.VERTICAL_STACKED_BAR, width, 250);
<a name="line886"></a>  chart.setTitle(title);
<a name="line887"></a>  chart.addDataSet(data, &#39;ff9900&#39;);
<a name="line888"></a>  chart.setLeftLabels(ylabels);
<a name="line889"></a>  chart.setGridY(ylabels.length - 1);
<a name="line890"></a>  chart.setXLabels(xlabels);
<a name="line891"></a>  chart.render(this.statsEl_);
<a name="line892"></a>};
<a name="line893"></a>
<a name="line894"></a>
<a name="line895"></a>/**
<a name="line896"></a> * Draws a pie chart showing the percentage of time spent running the tests
<a name="line897"></a> * compared to loading them etc.
<a name="line898"></a> * @private
<a name="line899"></a> */
<a name="line900"></a>goog.testing.MultiTestRunner.prototype.drawRunTimePie_ = function() {
<a name="line901"></a>  var totalTime = 0, runTime = 0;
<a name="line902"></a>  for (var i = 0; i &lt; this.stats_.length; i++) {
<a name="line903"></a>    var stat = this.stats_[i];
<a name="line904"></a>    totalTime += stat.totalTime;
<a name="line905"></a>    runTime += stat.runTime;
<a name="line906"></a>  }
<a name="line907"></a>  var loadTime = totalTime - runTime;
<a name="line908"></a>  var pie = new goog.ui.ServerChart(
<a name="line909"></a>      goog.ui.ServerChart.ChartType.PIE, 500, 250);
<a name="line910"></a>  pie.setMinValue(0);
<a name="line911"></a>  pie.setMaxValue(totalTime);
<a name="line912"></a>  pie.addDataSet([runTime, loadTime], &#39;ff9900&#39;);
<a name="line913"></a>  pie.setXLabels([
<a name="line914"></a>      &#39;Test execution (&#39; + runTime + &#39;ms)&#39;,
<a name="line915"></a>      &#39;Loading (&#39; + loadTime + &#39;ms)&#39;]);
<a name="line916"></a>  pie.render(this.statsEl_);
<a name="line917"></a>};
<a name="line918"></a>
<a name="line919"></a>
<a name="line920"></a>/**
<a name="line921"></a> * Draws a pie chart showing the percentage of time spent running the tests
<a name="line922"></a> * compared to loading them etc.
<a name="line923"></a> * @private
<a name="line924"></a> */
<a name="line925"></a>goog.testing.MultiTestRunner.prototype.drawWorstTestsTable_ = function() {
<a name="line926"></a>  this.stats_.sort(function(a, b) {
<a name="line927"></a>    return b[&#39;numFilesLoaded&#39;] - a[&#39;numFilesLoaded&#39;];
<a name="line928"></a>  });
<a name="line929"></a>
<a name="line930"></a>  var tbody = goog.bind(this.dom_.createDom, this.dom_, &#39;tbody&#39;);
<a name="line931"></a>  var thead = goog.bind(this.dom_.createDom, this.dom_, &#39;thead&#39;);
<a name="line932"></a>  var tr = goog.bind(this.dom_.createDom, this.dom_, &#39;tr&#39;);
<a name="line933"></a>  var th = goog.bind(this.dom_.createDom, this.dom_, &#39;th&#39;);
<a name="line934"></a>  var td = goog.bind(this.dom_.createDom, this.dom_, &#39;td&#39;);
<a name="line935"></a>  var a = goog.bind(this.dom_.createDom, this.dom_, &#39;a&#39;);
<a name="line936"></a>
<a name="line937"></a>  var head = thead({&#39;style&#39;: &#39;cursor: pointer&#39;},
<a name="line938"></a>      tr(null,
<a name="line939"></a>          th(null, &#39; &#39;),
<a name="line940"></a>          th(null, &#39;Test file&#39;),
<a name="line941"></a>          th(&#39;center&#39;, &#39;Num files loaded&#39;),
<a name="line942"></a>          th(&#39;center&#39;, &#39;Run time (ms)&#39;),
<a name="line943"></a>          th(&#39;center&#39;, &#39;Total time (ms)&#39;)));
<a name="line944"></a>  var body = tbody();
<a name="line945"></a>  var table = this.dom_.createDom(&#39;table&#39;, null, head, body);
<a name="line946"></a>
<a name="line947"></a>  for (var i = 0; i &lt; this.stats_.length; i++) {
<a name="line948"></a>    var stat = this.stats_[i];
<a name="line949"></a>    body.appendChild(tr(null,
<a name="line950"></a>        td(&#39;center&#39;, String(i + 1)),
<a name="line951"></a>        td(null, a(
<a name="line952"></a>            {&#39;href&#39;: this.basePath_ + stat[&#39;testFile&#39;], &#39;target&#39;: &#39;_blank&#39;},
<a name="line953"></a>            stat[&#39;testFile&#39;])),
<a name="line954"></a>        td(&#39;center&#39;, String(stat[&#39;numFilesLoaded&#39;])),
<a name="line955"></a>        td(&#39;center&#39;, String(stat[&#39;runTime&#39;])),
<a name="line956"></a>        td(&#39;center&#39;, String(stat[&#39;totalTime&#39;]))));
<a name="line957"></a>  }
<a name="line958"></a>
<a name="line959"></a>  this.statsEl_.appendChild(table);
<a name="line960"></a>
<a name="line961"></a>  this.tableSorter_.setDefaultSortFunction(goog.ui.TableSorter.numericSort);
<a name="line962"></a>  this.tableSorter_.setSortFunction(
<a name="line963"></a>      1 /* test file name */, goog.ui.TableSorter.alphaSort);
<a name="line964"></a>  this.tableSorter_.decorate(table);
<a name="line965"></a>};
<a name="line966"></a>
<a name="line967"></a>
<a name="line968"></a>/**
<a name="line969"></a> * Clears the stats page.
<a name="line970"></a> * @private
<a name="line971"></a> */
<a name="line972"></a>goog.testing.MultiTestRunner.prototype.clearStats_ = function() {
<a name="line973"></a>  goog.dom.removeChildren(this.statsEl_);
<a name="line974"></a>};
<a name="line975"></a>
<a name="line976"></a>
<a name="line977"></a>/**
<a name="line978"></a> * Updates the report&#39;s summary.
<a name="line979"></a> * @private
<a name="line980"></a> */
<a name="line981"></a>goog.testing.MultiTestRunner.prototype.writeCurrentSummary_ = function() {
<a name="line982"></a>  var total = this.activeTests_.length;
<a name="line983"></a>  var executed = this.resultCount_;
<a name="line984"></a>  var passes = this.passes_;
<a name="line985"></a>  var duration = Math.round((goog.now() - this.startTime_) / 1000);
<a name="line986"></a>  var text = executed + &#39; of &#39; + total + &#39; tests executed.&lt;br&gt;&#39; +
<a name="line987"></a>      passes + &#39; passed, &#39; + (executed - passes) + &#39; failed.&lt;br&gt;&#39; +
<a name="line988"></a>      &#39;Duration: &#39; + duration + &#39;s.&#39;;
<a name="line989"></a>  this.reportEl_.firstChild.innerHTML = text;
<a name="line990"></a>};
<a name="line991"></a>
<a name="line992"></a>
<a name="line993"></a>/**
<a name="line994"></a> * Adds a segment to the progress bar.
<a name="line995"></a> * @param {string} title Title for the segment.
<a name="line996"></a> * @param {*} success Whether the segment should indicate a success.
<a name="line997"></a> * @private
<a name="line998"></a> */
<a name="line999"></a>goog.testing.MultiTestRunner.prototype.drawProgressSegment_ =
<a name="line1000"></a>      function(title, success) {
<a name="line1001"></a>  var part = this.progressRow_.cells[this.resultCount_ - 1];
<a name="line1002"></a>  part.title = title + &#39; : &#39; + (success ? &#39;SUCCESS&#39; : &#39;FAILURE&#39;);
<a name="line1003"></a>  part.style.backgroundColor = success ? &#39;#090&#39; : &#39;#900&#39;;
<a name="line1004"></a>};
<a name="line1005"></a>
<a name="line1006"></a>
<a name="line1007"></a>/**
<a name="line1008"></a> * Draws a test result in the report pane.
<a name="line1009"></a> * @param {string} test Test name.
<a name="line1010"></a> * @param {*} success Whether the test succeeded.
<a name="line1011"></a> * @param {string} report The report.
<a name="line1012"></a> * @private
<a name="line1013"></a> */
<a name="line1014"></a>goog.testing.MultiTestRunner.prototype.drawTestResult_ = function(
<a name="line1015"></a>    test, success, report) {
<a name="line1016"></a>  var text = goog.string.isEmpty(report) ?
<a name="line1017"></a>      &#39;No report for &#39; + test + &#39;\n&#39; : report;
<a name="line1018"></a>  var el = this.dom_.createDom(&#39;div&#39;);
<a name="line1019"></a>  text = goog.string.htmlEscape(text).replace(/\n/g, &#39;&lt;br&gt;&#39;);
<a name="line1020"></a>  if (success) {
<a name="line1021"></a>    el.className = goog.getCssName(&#39;goog-testrunner-report-success&#39;);
<a name="line1022"></a>  } else {
<a name="line1023"></a>    text += &#39;&lt;a href=&quot;&#39; + this.basePath_ + test +
<a name="line1024"></a>        &#39;&quot;&gt;Run individually &amp;raquo;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&#39;;
<a name="line1025"></a>    el.className = goog.getCssName(&#39;goog-testrunner-report-failure&#39;);
<a name="line1026"></a>  }
<a name="line1027"></a>  el.innerHTML = text;
<a name="line1028"></a>  this.reportEl_.appendChild(el);
<a name="line1029"></a>};
<a name="line1030"></a>
<a name="line1031"></a>
<a name="line1032"></a>/**
<a name="line1033"></a> * Returns the current timestamp.
<a name="line1034"></a> * @return {string} HH:MM:SS.
<a name="line1035"></a> * @private
<a name="line1036"></a> */
<a name="line1037"></a>goog.testing.MultiTestRunner.prototype.getTimeStamp_ = function() {
<a name="line1038"></a>  var d = new Date;
<a name="line1039"></a>  return goog.string.padNumber(d.getHours(), 2) + &#39;:&#39; +
<a name="line1040"></a>      goog.string.padNumber(d.getMinutes(), 2) + &#39;:&#39; +
<a name="line1041"></a>      goog.string.padNumber(d.getSeconds(), 2);
<a name="line1042"></a>};
<a name="line1043"></a>
<a name="line1044"></a>
<a name="line1045"></a>/**
<a name="line1046"></a> * Trims a filename to be less than 35-characters, ensuring that we do not break
<a name="line1047"></a> * a path part.
<a name="line1048"></a> * @param {string} name The file name.
<a name="line1049"></a> * @return {string} The shortened name.
<a name="line1050"></a> * @private
<a name="line1051"></a> */
<a name="line1052"></a>goog.testing.MultiTestRunner.prototype.trimFileName_ = function(name) {
<a name="line1053"></a>  if (name.length &lt; 35) {
<a name="line1054"></a>    return name;
<a name="line1055"></a>  }
<a name="line1056"></a>  var parts = name.split(&#39;/&#39;);
<a name="line1057"></a>  var result = &#39;&#39;;
<a name="line1058"></a>  while (result.length &lt; 35 &amp;&amp; parts.length &gt; 0) {
<a name="line1059"></a>    result = &#39;/&#39; + parts.pop() + result;
<a name="line1060"></a>  }
<a name="line1061"></a>  return &#39;...&#39; + result;
<a name="line1062"></a>};
<a name="line1063"></a>
<a name="line1064"></a>
<a name="line1065"></a>/**
<a name="line1066"></a> * Shows the report and hides the log if the argument is true.
<a name="line1067"></a> * @param {number} tab Which tab to show.
<a name="line1068"></a> * @private
<a name="line1069"></a> */
<a name="line1070"></a>goog.testing.MultiTestRunner.prototype.showTab_ = function(tab) {
<a name="line1071"></a>  var activeTabCssClass = goog.getCssName(&#39;goog-testrunner-activetab&#39;);
<a name="line1072"></a>  if (tab == 0) {
<a name="line1073"></a>    this.logEl_.style.display = &#39;&#39;;
<a name="line1074"></a>    goog.dom.classes.add(this.logTabEl_, activeTabCssClass);
<a name="line1075"></a>  } else {
<a name="line1076"></a>    this.logEl_.style.display = &#39;none&#39;;
<a name="line1077"></a>    goog.dom.classes.remove(this.logTabEl_, activeTabCssClass);
<a name="line1078"></a>  }
<a name="line1079"></a>
<a name="line1080"></a>  if (tab == 1) {
<a name="line1081"></a>    this.reportEl_.style.display = &#39;&#39;;
<a name="line1082"></a>    goog.dom.classes.add(this.reportTabEl_, activeTabCssClass);
<a name="line1083"></a>  } else {
<a name="line1084"></a>    this.reportEl_.style.display = &#39;none&#39;;
<a name="line1085"></a>    goog.dom.classes.remove(this.reportTabEl_, activeTabCssClass);
<a name="line1086"></a>  }
<a name="line1087"></a>
<a name="line1088"></a>  if (tab == 2) {
<a name="line1089"></a>    this.statsEl_.style.display = &#39;&#39;;
<a name="line1090"></a>    goog.dom.classes.add(this.statsTabEl_, activeTabCssClass);
<a name="line1091"></a>  } else {
<a name="line1092"></a>    this.statsEl_.style.display = &#39;none&#39;;
<a name="line1093"></a>    goog.dom.classes.remove(this.statsTabEl_, activeTabCssClass);
<a name="line1094"></a>  }
<a name="line1095"></a>};
<a name="line1096"></a>
<a name="line1097"></a>
<a name="line1098"></a>/**
<a name="line1099"></a> * Handles the start button being clicked.
<a name="line1100"></a> * @param {goog.events.BrowserEvent} e The click event.
<a name="line1101"></a> * @private
<a name="line1102"></a> */
<a name="line1103"></a>goog.testing.MultiTestRunner.prototype.onStartClicked_ = function(e) {
<a name="line1104"></a>  this.start();
<a name="line1105"></a>};
<a name="line1106"></a>
<a name="line1107"></a>
<a name="line1108"></a>/**
<a name="line1109"></a> * Handles the stop button being clicked.
<a name="line1110"></a> * @param {goog.events.BrowserEvent} e The click event.
<a name="line1111"></a> * @private
<a name="line1112"></a> */
<a name="line1113"></a>goog.testing.MultiTestRunner.prototype.onStopClicked_ = function(e) {
<a name="line1114"></a>  this.stopped_ = true;
<a name="line1115"></a>  this.finish_();
<a name="line1116"></a>};
<a name="line1117"></a>
<a name="line1118"></a>
<a name="line1119"></a>/**
<a name="line1120"></a> * Handles the log tab being clicked.
<a name="line1121"></a> * @param {goog.events.BrowserEvent} e The click event.
<a name="line1122"></a> * @private
<a name="line1123"></a> */
<a name="line1124"></a>goog.testing.MultiTestRunner.prototype.onLogTabClicked_ = function(e) {
<a name="line1125"></a>  this.showTab_(0);
<a name="line1126"></a>};
<a name="line1127"></a>
<a name="line1128"></a>
<a name="line1129"></a>/**
<a name="line1130"></a> * Handles the log tab being clicked.
<a name="line1131"></a> * @param {goog.events.BrowserEvent} e The click event.
<a name="line1132"></a> * @private
<a name="line1133"></a> */
<a name="line1134"></a>goog.testing.MultiTestRunner.prototype.onReportTabClicked_ = function(e) {
<a name="line1135"></a>  this.showTab_(1);
<a name="line1136"></a>};
<a name="line1137"></a>
<a name="line1138"></a>
<a name="line1139"></a>/**
<a name="line1140"></a> * Handles the stats tab being clicked.
<a name="line1141"></a> * @param {goog.events.BrowserEvent} e The click event.
<a name="line1142"></a> * @private
<a name="line1143"></a> */
<a name="line1144"></a>goog.testing.MultiTestRunner.prototype.onStatsTabClicked_ = function(e) {
<a name="line1145"></a>  this.showTab_(2);
<a name="line1146"></a>};
<a name="line1147"></a>
<a name="line1148"></a>
<a name="line1149"></a>
<a name="line1150"></a>/**
<a name="line1151"></a> * Class used to manage the interaction with a single iframe.
<a name="line1152"></a> * @param {string} basePath The base path for tests.
<a name="line1153"></a> * @param {number} timeoutMs The time to wait for the test to load and run.
<a name="line1154"></a> * @param {boolean} verbosePasses Whether to show results for passes.
<a name="line1155"></a> * @param {goog.dom.DomHelper=} opt_domHelper Optional dom helper.
<a name="line1156"></a> * @constructor
<a name="line1157"></a> * @extends {goog.ui.Component}
<a name="line1158"></a> */
<a name="line1159"></a>goog.testing.MultiTestRunner.TestFrame = function(
<a name="line1160"></a>    basePath, timeoutMs, verbosePasses, opt_domHelper) {
<a name="line1161"></a>  goog.ui.Component.call(this, opt_domHelper);
<a name="line1162"></a>
<a name="line1163"></a>  /**
<a name="line1164"></a>   * Base path where tests should be resolved from.
<a name="line1165"></a>   * @type {string}
<a name="line1166"></a>   * @private
<a name="line1167"></a>   */
<a name="line1168"></a>  this.basePath_ = basePath;
<a name="line1169"></a>
<a name="line1170"></a>  /**
<a name="line1171"></a>   * The timeout for the test.
<a name="line1172"></a>   * @type {number}
<a name="line1173"></a>   * @private
<a name="line1174"></a>   */
<a name="line1175"></a>  this.timeoutMs_ = timeoutMs;
<a name="line1176"></a>
<a name="line1177"></a>  /**
<a name="line1178"></a>   * Whether to show a summary for passing tests.
<a name="line1179"></a>   * @type {boolean}
<a name="line1180"></a>   * @private
<a name="line1181"></a>   */
<a name="line1182"></a>  this.verbosePasses_ = verbosePasses;
<a name="line1183"></a>
<a name="line1184"></a>  /**
<a name="line1185"></a>   * An event handler for handling events.
<a name="line1186"></a>   * @type {goog.events.EventHandler}
<a name="line1187"></a>   * @private
<a name="line1188"></a>   */
<a name="line1189"></a>  this.eh_ = new goog.events.EventHandler(this);
<a name="line1190"></a>
<a name="line1191"></a>};
<a name="line1192"></a>goog.inherits(goog.testing.MultiTestRunner.TestFrame, goog.ui.Component);
<a name="line1193"></a>
<a name="line1194"></a>
<a name="line1195"></a>/**
<a name="line1196"></a> * Reference to the iframe.
<a name="line1197"></a> * @type {HTMLIFrameElement}
<a name="line1198"></a> * @private
<a name="line1199"></a> */
<a name="line1200"></a>goog.testing.MultiTestRunner.TestFrame.prototype.iframeEl_ = null;
<a name="line1201"></a>
<a name="line1202"></a>
<a name="line1203"></a>/**
<a name="line1204"></a> * Whether the iframe for the current test has loaded.
<a name="line1205"></a> * @type {boolean}
<a name="line1206"></a> * @private
<a name="line1207"></a> */
<a name="line1208"></a>goog.testing.MultiTestRunner.TestFrame.prototype.iframeLoaded_ = false;
<a name="line1209"></a>
<a name="line1210"></a>
<a name="line1211"></a>/**
<a name="line1212"></a> * The test file being run.
<a name="line1213"></a> * @type {string}
<a name="line1214"></a> * @private
<a name="line1215"></a> */
<a name="line1216"></a>goog.testing.MultiTestRunner.TestFrame.prototype.testFile_ = &#39;&#39;;
<a name="line1217"></a>
<a name="line1218"></a>
<a name="line1219"></a>/**
<a name="line1220"></a> * The report returned from the test.
<a name="line1221"></a> * @type {string}
<a name="line1222"></a> * @private
<a name="line1223"></a> */
<a name="line1224"></a>goog.testing.MultiTestRunner.TestFrame.prototype.report_ = &#39;&#39;;
<a name="line1225"></a>
<a name="line1226"></a>
<a name="line1227"></a>/**
<a name="line1228"></a> * The total time loading and running the test in milliseconds.
<a name="line1229"></a> * @type {number}
<a name="line1230"></a> * @private
<a name="line1231"></a> */
<a name="line1232"></a>goog.testing.MultiTestRunner.TestFrame.prototype.totalTime_ = 0;
<a name="line1233"></a>
<a name="line1234"></a>
<a name="line1235"></a>/**
<a name="line1236"></a> * The actual runtime of the test in milliseconds.
<a name="line1237"></a> * @type {number}
<a name="line1238"></a> * @private
<a name="line1239"></a> */
<a name="line1240"></a>goog.testing.MultiTestRunner.TestFrame.prototype.runTime_ = 0;
<a name="line1241"></a>
<a name="line1242"></a>
<a name="line1243"></a>/**
<a name="line1244"></a> * The number of files loaded by the test.
<a name="line1245"></a> * @type {number}
<a name="line1246"></a> * @private
<a name="line1247"></a> */
<a name="line1248"></a>goog.testing.MultiTestRunner.TestFrame.prototype.numFilesLoaded_ = 0;
<a name="line1249"></a>
<a name="line1250"></a>
<a name="line1251"></a>/**
<a name="line1252"></a> * Whether the test was successful, null if no result has been returned yet.
<a name="line1253"></a> * @type {?boolean}
<a name="line1254"></a> * @private
<a name="line1255"></a> */
<a name="line1256"></a>goog.testing.MultiTestRunner.TestFrame.prototype.isSuccess_ = null;
<a name="line1257"></a>
<a name="line1258"></a>
<a name="line1259"></a>/**
<a name="line1260"></a> * Timestamp for the when the test was started.
<a name="line1261"></a> * @type {number}
<a name="line1262"></a> * @private
<a name="line1263"></a> */
<a name="line1264"></a>goog.testing.MultiTestRunner.TestFrame.prototype.startTime_ = 0;
<a name="line1265"></a>
<a name="line1266"></a>
<a name="line1267"></a>/**
<a name="line1268"></a> * Timestamp for the last state, used to determine timeouts.
<a name="line1269"></a> * @type {number}
<a name="line1270"></a> * @private
<a name="line1271"></a> */
<a name="line1272"></a>goog.testing.MultiTestRunner.TestFrame.prototype.lastStateTime_ = 0;
<a name="line1273"></a>
<a name="line1274"></a>
<a name="line1275"></a>/**
<a name="line1276"></a> * The state of the active test.
<a name="line1277"></a> * @type {number}
<a name="line1278"></a> * @private
<a name="line1279"></a> */
<a name="line1280"></a>goog.testing.MultiTestRunner.TestFrame.prototype.currentState_ = 0;
<a name="line1281"></a>
<a name="line1282"></a>
<a name="line1283"></a>/** @override */
<a name="line1284"></a>goog.testing.MultiTestRunner.TestFrame.prototype.disposeInternal = function() {
<a name="line1285"></a>  goog.testing.MultiTestRunner.TestFrame.superClass_.disposeInternal.call(this);
<a name="line1286"></a>  this.dom_.removeNode(this.iframeEl_);
<a name="line1287"></a>  this.eh_.dispose();
<a name="line1288"></a>  this.iframeEl_ = null;
<a name="line1289"></a>};
<a name="line1290"></a>
<a name="line1291"></a>
<a name="line1292"></a>/**
<a name="line1293"></a> * Runs a test file in this test frame.
<a name="line1294"></a> * @param {string} testFile The test to run.
<a name="line1295"></a> */
<a name="line1296"></a>goog.testing.MultiTestRunner.TestFrame.prototype.runTest = function(testFile) {
<a name="line1297"></a>  this.lastStateTime_ = this.startTime_ = goog.now();
<a name="line1298"></a>
<a name="line1299"></a>  if (!this.iframeEl_) {
<a name="line1300"></a>    this.createIframe_();
<a name="line1301"></a>  }
<a name="line1302"></a>
<a name="line1303"></a>  this.iframeLoaded_ = false;
<a name="line1304"></a>  this.currentState_ = 0;
<a name="line1305"></a>  this.isSuccess_ = null;
<a name="line1306"></a>  this.report_ = &#39;&#39;;
<a name="line1307"></a>  this.testFile_ = testFile;
<a name="line1308"></a>
<a name="line1309"></a>  try {
<a name="line1310"></a>    this.iframeEl_.src = this.basePath_ + testFile;
<a name="line1311"></a>  } catch (e) {
<a name="line1312"></a>    // Failures will trigger a JS exception on the local file system.
<a name="line1313"></a>    this.report_ = this.testFile_ + &#39; failed to load : &#39; + e.message;
<a name="line1314"></a>    this.isSuccess_ = false;
<a name="line1315"></a>    this.finish_();
<a name="line1316"></a>    return;
<a name="line1317"></a>  }
<a name="line1318"></a>
<a name="line1319"></a>  this.checkForCompletion_();
<a name="line1320"></a>};
<a name="line1321"></a>
<a name="line1322"></a>
<a name="line1323"></a>/**
<a name="line1324"></a> * @return {string} The test file the TestFrame is running.
<a name="line1325"></a> */
<a name="line1326"></a>goog.testing.MultiTestRunner.TestFrame.prototype.getTestFile = function() {
<a name="line1327"></a>  return this.testFile_;
<a name="line1328"></a>};
<a name="line1329"></a>
<a name="line1330"></a>
<a name="line1331"></a>/**
<a name="line1332"></a> * @return {Object} Stats about the test run.
<a name="line1333"></a> */
<a name="line1334"></a>goog.testing.MultiTestRunner.TestFrame.prototype.getStats = function() {
<a name="line1335"></a>  return {
<a name="line1336"></a>    &#39;testFile&#39;: this.testFile_,
<a name="line1337"></a>    &#39;success&#39;: this.isSuccess_,
<a name="line1338"></a>    &#39;runTime&#39;: this.runTime_,
<a name="line1339"></a>    &#39;totalTime&#39;: this.totalTime_,
<a name="line1340"></a>    &#39;numFilesLoaded&#39;: this.numFilesLoaded_
<a name="line1341"></a>  };
<a name="line1342"></a>};
<a name="line1343"></a>
<a name="line1344"></a>
<a name="line1345"></a>/**
<a name="line1346"></a> * @return {string} The report for the test run.
<a name="line1347"></a> */
<a name="line1348"></a>goog.testing.MultiTestRunner.TestFrame.prototype.getReport = function() {
<a name="line1349"></a>  return this.report_;
<a name="line1350"></a>};
<a name="line1351"></a>
<a name="line1352"></a>
<a name="line1353"></a>/**
<a name="line1354"></a> * @return {?boolean} Whether the test frame had a success.
<a name="line1355"></a> */
<a name="line1356"></a>goog.testing.MultiTestRunner.TestFrame.prototype.isSuccess = function() {
<a name="line1357"></a>  return this.isSuccess_;
<a name="line1358"></a>};
<a name="line1359"></a>
<a name="line1360"></a>
<a name="line1361"></a>/**
<a name="line1362"></a> * Handles the TestFrame finishing a single test.
<a name="line1363"></a> * @private
<a name="line1364"></a> */
<a name="line1365"></a>goog.testing.MultiTestRunner.TestFrame.prototype.finish_ = function() {
<a name="line1366"></a>  this.totalTime_ = goog.now() - this.startTime_;
<a name="line1367"></a>  // TODO(user): Fire an event instead?
<a name="line1368"></a>  if (this.getParent() &amp;&amp; this.getParent().processResult) {
<a name="line1369"></a>    this.getParent().processResult(this);
<a name="line1370"></a>  }
<a name="line1371"></a>};
<a name="line1372"></a>
<a name="line1373"></a>
<a name="line1374"></a>/**
<a name="line1375"></a> * Creates an iframe to run the tests in.  For overriding in unit tests.
<a name="line1376"></a> * @private
<a name="line1377"></a> */
<a name="line1378"></a>goog.testing.MultiTestRunner.TestFrame.prototype.createIframe_ = function() {
<a name="line1379"></a>  this.iframeEl_ =
<a name="line1380"></a>      /** @type {HTMLIFrameElement} */ (this.dom_.createDom(&#39;iframe&#39;));
<a name="line1381"></a>  this.getElement().appendChild(this.iframeEl_);
<a name="line1382"></a>  this.eh_.listen(this.iframeEl_, &#39;load&#39;, this.onIframeLoaded_);
<a name="line1383"></a>};
<a name="line1384"></a>
<a name="line1385"></a>
<a name="line1386"></a>/**
<a name="line1387"></a> * Handles the iframe loading.
<a name="line1388"></a> * @param {goog.events.BrowserEvent} e The load event.
<a name="line1389"></a> * @private
<a name="line1390"></a> */
<a name="line1391"></a>goog.testing.MultiTestRunner.TestFrame.prototype.onIframeLoaded_ = function(e) {
<a name="line1392"></a>  this.iframeLoaded_ = true;
<a name="line1393"></a>};
<a name="line1394"></a>
<a name="line1395"></a>
<a name="line1396"></a>/**
<a name="line1397"></a> * Checks the active test for completion, keeping track of the tests&#39; various
<a name="line1398"></a> * execution stages.
<a name="line1399"></a> * @private
<a name="line1400"></a> */
<a name="line1401"></a>goog.testing.MultiTestRunner.TestFrame.prototype.checkForCompletion_ =
<a name="line1402"></a>    function() {
<a name="line1403"></a>  var js = goog.dom.getFrameContentWindow(this.iframeEl_);
<a name="line1404"></a>  switch (this.currentState_) {
<a name="line1405"></a>    case 0:
<a name="line1406"></a>      if (this.iframeLoaded_ &amp;&amp; js[&#39;G_testRunner&#39;]) {
<a name="line1407"></a>        this.lastStateTime_ = goog.now();
<a name="line1408"></a>        this.currentState_++;
<a name="line1409"></a>      }
<a name="line1410"></a>      break;
<a name="line1411"></a>    case 1:
<a name="line1412"></a>      if (js[&#39;G_testRunner&#39;][&#39;isInitialized&#39;]()) {
<a name="line1413"></a>        this.lastStateTime_ = goog.now();
<a name="line1414"></a>        this.currentState_++;
<a name="line1415"></a>      }
<a name="line1416"></a>      break;
<a name="line1417"></a>    case 2:
<a name="line1418"></a>      if (js[&#39;G_testRunner&#39;][&#39;isFinished&#39;]()) {
<a name="line1419"></a>        var tr = js[&#39;G_testRunner&#39;];
<a name="line1420"></a>        this.isSuccess_ = tr[&#39;isSuccess&#39;]();
<a name="line1421"></a>        this.report_ = tr[&#39;getReport&#39;](this.verbosePasses_);
<a name="line1422"></a>        this.runTime_ = tr[&#39;getRunTime&#39;]();
<a name="line1423"></a>        this.numFilesLoaded_ = tr[&#39;getNumFilesLoaded&#39;]();
<a name="line1424"></a>        this.finish_();
<a name="line1425"></a>        return;
<a name="line1426"></a>      }
<a name="line1427"></a>  }
<a name="line1428"></a>
<a name="line1429"></a>  // Check to see if the test has timed out.
<a name="line1430"></a>  if (goog.now() - this.lastStateTime_ &gt; this.timeoutMs_) {
<a name="line1431"></a>    this.report_ = this.testFile_ + &#39; timed out  &#39; +
<a name="line1432"></a>        goog.testing.MultiTestRunner.STATES[this.currentState_];
<a name="line1433"></a>    this.isSuccess_ = false;
<a name="line1434"></a>    this.finish_();
<a name="line1435"></a>    return;
<a name="line1436"></a>  }
<a name="line1437"></a>
<a name="line1438"></a>  // Check again in 100ms.
<a name="line1439"></a>  goog.Timer.callOnce(this.checkForCompletion_, 100, this);
<a name="line1440"></a>};
</pre>


</body>
</html>
